package exp.parser;

import grammar.parser.FuncFParams;
import word.parser.WordElement;

import java.util.ArrayList;
import java.util.List;

public class MulExp extends ExpParser {
    private final ExpParser left;
    private final ExpParser right;
    private final MulOpt opt;

    public MulExp(ExpParser left, ExpParser right, MulOpt opt) {
        super(left.isComputable() && (right == null || right.isComputable()),
                left.isConst() && (right == null || right.isConst()));
        this.left = left;
        this.right = right;
        this.opt = opt;
    }

    public enum MulOpt {
        MULT,
        DIV,
        MOD
    }

    public static MulExp parseMulExp() {
        ExpParser left;
        left = UnaryExp.parseUnaryExp();
        List<ExpParser> expParserList = new ArrayList<>();
        expParserList.add(left);
        List<MulOpt> mulOptList = new ArrayList<>();
        while (getAnalyzingWord().getType() == WordElement.WordType.MULT ||
                getAnalyzingWord().getType() == WordElement.WordType.DIV ||
                getAnalyzingWord().getType() == WordElement.WordType.MOD) {
            MulOpt opt;
            if (getAnalyzingWord().getType() == WordElement.WordType.DIV) {
                opt = MulOpt.DIV;
            } else if (getAnalyzingWord().getType() == WordElement.WordType.MOD) {
                opt = MulOpt.MOD;
            } else {
                opt = MulOpt.MULT;
            }
            mulOptList.add(opt);
            analyzeNextWord();
            expParserList.add(UnaryExp.parseUnaryExp());
        }
        mulOptList.add(null);
        for (int i = 1; i <= expParserList.size(); i++) {
            ExpParser right = i < expParserList.size() ? expParserList.get(i) : null;
            MulOpt opt = mulOptList.get(i - 1);
            left = new MulExp(left, right, opt);
        }
        return (MulExp) left;
    }

    @Override
    public LVal toLVal() {
        if (right == null) {
            return left.toLVal();
        }
        return null;
    }

    @Override
    public Integer compute() {
        Integer value = null;
        if (isComputable()) {
            value = left.getValue();
            if (right != null) {
                switch (opt) {
                    case DIV:
                        value /= right.getValue();
                        break;
                    case MULT:
                        value *= right.getValue();
                        break;
                    case MOD:
                        value %= right.getValue();
                        break;
                }
            }
        }
        return value;
    }

    @Override
    public FuncFParams.FuncFParam checkDimension() {
        if (right != null) {
            return new FuncFParams.FuncFParam(0, 0);
        }
        return left.checkDimension();
    }

}
